package jmcnet.libcommun.security
{
	import com.adobe.cairngorm.CairngormError;
	import com.adobe.cairngorm.CairngormMessageCodes;
	
	import flash.events.EventDispatcher;
	import flash.utils.getQualifiedClassName;
	
	import jmcnet.libcommun.communs.JMCNetLibCommunHelper;
	import jmcnet.libcommun.communs.helpers.HelperString;
	import jmcnet.libcommun.logger.JMCNetLogger;
	
	import mx.managers.PopUpManager;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	
	/**
	 * Dispatched when the user logs in with success.
	 * @eventType	jmcnet.libcommun.security.EventLogin.LOGIN_OK
	 * @see			EventLogin#LOGIN_OK
	 */
	[Event(name="loginOK", type="jmcnet.libcommun.security.EventLogin")]
	
	/**
	 * Dispatched when the user logs out with success.
	 * @eventType	jmcnet.libcommun.security.EventLogin.LOGOUT_OK
	 * @see			EventLogin#LOGOUT_OK
	 */
	[Event(name="logoutOK", type="jmcnet.libcommun.security.EventLogin")]
	
	/**
	 * Dispatched when the user logs in with error or abandonne the login
	 * @eventType	jmcnet.libcommun.security.EventLogin.LOGIN_KO
	 * @see			EventLogin#LOGIN_KO
	 */
	[Event(name="loginKO", type="jmcnet.libcommun.security.EventLogin")]
	
	/**
	 * Dispatched when the user logs in with wrong credentials
	 * @eventType	jmcnet.libcommun.security.EventLogin.LOGIN_BAD_CREDENTIALS
	 * @see			EventLogin#LOGIN_KO
	 */
	[Event(name="loginBadCredentials", type="jmcnet.libcommun.security.EventLogin")]
	
	/**
	 * Dispatched when the user is disabled
	 * @eventType	jmcnet.libcommun.security.EventLogin.LOGIN_USER_DISABLED
	 * @see			EventLogin#LOGIN_USER_DISABLED
	 */
	[Event(name="loginUserDisabled", type="jmcnet.libcommun.security.EventLogin")]
	
	/**
	 * Classe de base abstraite du gestionnaire de session. Pour être utilisable, l'utilisateur doit
	 * appeler BaseSessionManager.sessionManager = new SessionManagerxxxImpl();
	 * L'utilisation se fait ensuite par BaseSessionManager.sessionManager.xxx();
	 */
	public class BaseSessionManager extends EventDispatcher {
		private static var _instance:BaseSessionManager;
		private static var _loginWindowClass:Class=LoginWindow;
		private var _principal:String=null;
		private var _authentified:Boolean=false;
		private var _roles:Array = new Array();
		
		public function BaseSessionManager() {
			if ( getQualifiedClassName(super) == "BaseSessionManager" )
				throw new CairngormError(CairngormMessageCodes.ABSTRACT_METHOD_CALLED, "BaseSessionManager ne peut pas être instanciée car Abstract");
		}
		
		public static function get sessionManager():BaseSessionManager {
			if (_instance == null) {
				throw new CairngormError(CairngormMessageCodes.SINGLETON_EXCEPTION, "BaseSessionManager n'a pas été instanciée");
			}
			
			return _instance;
		}
		
		public static function set sessionManager(instance:BaseSessionManager):void {
			_instance = instance;
		}
		
		public static function get loginWindowClass():Class {
			return _loginWindowClass;
		}
		
		public static function set loginWindowClass(loginWindowClass:Class):void {
			_loginWindowClass = loginWindowClass;
		}
		
		public function get principal():String { return _principal;};
		public function set principal(principal:String):void { this._principal = principal;};
		
		public function onAuthentication(principal:String, result:Boolean, faultCode:String=null, reason:String=null):void {
			JMCNetLogger.debug("Appel BaseSessionManager.onAuthentication principal="+principal+" result="+result+" faultCode="+faultCode+" reason="+reason);
			var event:EventLogin;
			if (result) {
				JMCNetLogger.info("BaseSessionManager.onAuthentication : On est authentifié avec le login : '"+principal+"'");
				_authentified = result;
				this.principal = principal;
				// BlazeDS 4 -> les roles sont rapatries avant
				// retrieveSecurityRoles();
				event= new EventLogin(EventLogin.LOGIN_OK, principal);
				this.dispatchEvent(event);
				
				// On ferme la popup
				if (popup != null) {
					PopUpManager.removePopUp(popup);
				}
			}
			else {
				var previouslyAuthentified:Boolean = _authentified;
				_authentified = result;
				this.principal = null;
				this.roles = new Array();
				
				if (previouslyAuthentified) {
					JMCNetLogger.info("BaseSessionManager.onAuthentication : On n'est plus authentifié.");
					event=new EventLogin(EventLogin.LOGOUT_OK, principal, reason);
					this.dispatchEvent(event);
				}
				else {
					// Bad credentials en renvoyé par BlazeDS lorsque le mdp est incorrect. User not found est renvoyé par UserDetailImpl de la version e-Atipa.
					if (reason == "Bad credentials" || reason == "User not found" || reason == "There was an unhandled failure on the server. Bad credentials") {
						JMCNetLogger.info("BaseSessionManager.onAuthentication : L'authentification a échouée pour cause de '"+reason+"'.");
						event=new EventLogin(EventLogin.LOGIN_BAD_CREDENTIALS, principal, "Login ou mot de passe incorrect");
					}
					else if (reason == "Cannot re-authenticate in the same session.") {
						JMCNetLogger.info("BaseSessionManager.onAuthentication : L'authentification a échouée car le channel est déjà authentifié");
						_authentified = true;
						// On tente une deconnexion
						closeSession();
						event=new EventLogin(EventLogin.LOGIN_KO, principal, "La communication est déjà établie avec le serveur.");
					}
					else if (reason == "User is disabled") {
						JMCNetLogger.info("BaseSessionManager.onAuthentication : L'authentification a échouée car le compte est désactivé");
						_authentified = false;
						event=new EventLogin(EventLogin.LOGIN_USER_DISABLED, principal, "Le compte de l'utilisateur est désactivé.");
					}
					else {
						JMCNetLogger.info("BaseSessionManager.onAuthentication : L'authentification a échouée pour une raison inconnue : '"+reason+"'");
						event=new EventLogin(EventLogin.LOGIN_KO, principal, reason);
					}
					
					this.dispatchEvent(event);
				}
			}
			
			JMCNetLogger.debug("Fin BaseSessionManager.onAuthentication");
		}
		
		public function get authentified():Boolean { return _authentified;};
		
		public function set roles(roles:Array):void { _roles = roles;};
		public function get roles():Array { return _roles;};
		
		public function isUserInRole(role:String):Boolean {
			JMCNetLogger.debug("Appel BaseSessionManager.isUserInRole role='"+role+"'");
			if (!authentified || _principal == null) {
				JMCNetLogger.debug("Pas authentifié ou pas de principal -> false");
				return false;
			}
			
			var res:Boolean = HelperString.isContenuDans(role, _roles);
			
			JMCNetLogger.debug("Fin BaseSessionManager.isUserInRole : Role trouvé ? "+res);
			return res;
		}
		
		private var popup:BaseLoginWindow=null;
		public function openLoginWindow():BaseLoginWindow {
			if (BaseSessionManager.loginWindowClass != null) {
				popup = PopUpManager.createPopUp(JMCNetLibCommunHelper.mainAppDisplay, BaseSessionManager.loginWindowClass, true) as BaseLoginWindow;
				PopUpManager.centerPopUp(popup);
			}
			
			return popup;
		}
		
		
       	protected function onCloseSessionResult(evt:ResultEvent, token:Object=null):void {
			JMCNetLogger.debug("Appel BaseSessionManager.onCloseSessionResult");
			onAuthentication(null, false);
			JMCNetLogger.debug("Fin BaseSessionManager.onCloseSessionResult OK");
		}
		
		protected function onError(evt:FaultEvent, token:Object=null):void {
			JMCNetLogger.debug("Appel BaseSessionManager.onError evt="+evt.fault.faultString);
			JMCNetLogger.debug("Fin BaseSessionManager.onError OK");
		}
			
		public function closeSession():void {
			throw new UninitializedError("Surcharge de BaseSessionManager.closeSession obligatoire car Abstract");
		}
		
		public function openSession(login:String, password:String):void {
			throw new UninitializedError("Surcharge de BaseSessionManager.openSession obligatoire car Abstract");
		}
		
		public function retrieveSecurityRoles():void {
			throw new UninitializedError("Surcharge de BaseSessionManager.reopenSession obligatoire car Abstract");
		}
		
		protected function onGetRolesResult(event:ResultEvent, token:Object=null):void {
			throw new UninitializedError("Surcharge de BaseSessionManager.onGetRolesResult obligatoire car Abstract");
		} 	
	}
}